package com.mjk.common.web.getway.restful.prototal.ws.soap.proxy;


import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.util.StrUtils;
import com.mjk.common.web.getway.restful.prototal.ws.soap.annotation.BeeSoapMethod;
import groovy.lang.GroovyClassLoader;
import jakarta.jws.WebParam;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class BeeSoapProxy {

	/**
     * 自定义newProxyInstance方法，传入自定义TXClassLoader
     * @param classLoader TXClassLoader
     * @param interfaces Class<?>[]
     * @param h TXInvocationHandler
     */
    public static Object newProxyInstance(BeeSoapClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h,GroovyClassLoader groovyClassLoader) {

    		if(null == groovyClassLoader) {
    			groovyClassLoader = new GroovyClassLoader();
    		}
            // 1、生成源代码          
            String proxySrc = generateSrc(interfaces[0]);
            //System.out.println(proxySrc);
            groovyClassLoader.addClasspath(interfaces[0].getName());
            //System.out.println(proxySrc);
            //里面的文本是Java代码,但是我们可以看到这是一个字符串我们可以直接生成对应的Class<?>对象,而不需要我们写一个.java文件
            Class<?> clazz = groovyClassLoader.parseClass(proxySrc);              
            // 5.返回被代理后的代理对象
		try {
            Constructor<?> instance = clazz.getConstructor(InvocationHandler.class);
            return instance.newInstance(h);
        } catch (Exception e) {
          //do noting
            BizLogger.error(e);
        }finally{
        	 try {
				Objects.requireNonNull(groovyClassLoader).close();
			} catch (IOException e) {
                 //do noting
                 BizLogger.error(e);
			}
        }
        return null;
    }

    /**
     * 生成源代码
     */
    private static String generateSrc(Class<?> interfaces) {

        StringBuilder src = new StringBuilder(
                """
                package com.mjk.common.web.soap.proxy;
                import java.lang.reflect.Method;
                import jakarta.jws.WebService;
                        import com.mjk.common.tools.xml.XmlUtils;
                import com.mjk.common.tools.gson.GsonUtils;
                import com.mjk.common.web.getway.restful.prototal.ws.soap.annotation.BeeSoapMethod;
                import com.mjk.common.web.getway.restful.prototal.ws.soap.annotation.BeeSoapMethod.ResponseType;
                import jakarta.jws.WebParam;
                import jakarta.jws.WebMethod;
                import java.lang.reflect.InvocationHandler;
                """
        );
		// 换行符
		String ln = "\r\n";
		src.append("import ").append(interfaces.getName()).append(";").append(ln);
        src.append("@WebService(targetNamespace=\"http://").append(getUnSeqPackage(interfaces.getPackage().getName())).append("/\")").append(ln);
        src.append("public class ").append(interfaces.getSimpleName()).append("$Proxy0 implements ").append(interfaces.getSimpleName()).append("{").append(ln);
        src.append("InvocationHandler h;" + ln);
        src.append("public ").append(interfaces.getSimpleName()).append("$Proxy0(InvocationHandler h) {").append(ln);
        src.append("this.h = h;" + ln);
        src.append("}" + ln);
        for (Method m : interfaces.getMethods()) {
        	List<String> paramsStr = new ArrayList<>();
        	List<String> clazzStr = new ArrayList<>();
        	List<String> paramsValue = new ArrayList<>();
        	for(Parameter p : m.getParameters()){
        		WebParam param = p.getAnnotation(WebParam.class);
        		if(param == null) {
        			paramsValue.add(p.getName());
        			paramsStr.add(p.getParameterizedType().getTypeName()+" "+p.getName());
        		}else {
        			paramsValue.add(param.name());
        			paramsStr.add(p.getParameterizedType().getTypeName()+" "+param.name());
        		}
        		clazzStr.add( p.getParameterizedType().getTypeName()+".class");
        	}
        	src.append("@WebMethod" + ln);
        	BeeSoapMethod soapMethod = m.getAnnotation(BeeSoapMethod.class);
        	if(null!=soapMethod){
        		src.append("@BeeSoapMethod(work=\"").append(soapMethod.work()).append("\",method=\"").append(soapMethod.method()).append("\",reqType=ResponseType.").append(soapMethod.reqType()).append(",rspType=ResponseType.").append(soapMethod.rspType()).append(")").append(ln);
        	}
            src.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(").append(StrUtils.join(paramsStr, ",")).append("){").append(ln);
            src.append("try{" + ln);
            src.append("Method m = ").append(interfaces.getSimpleName()).append(".class.getMethod(\"").append(m.getName()).append("\",[").append(StrUtils.join(clazzStr, ",")).append("] as Class[]);").append(ln);
            src.append("BeeSoapMethod soap = m.getAnnotation(BeeSoapMethod.class);" + ln);
            src.append("if(soap!=null) {" + ln);
            	src.append("ResponseType type = soap.reqType();" + ln);
            	src.append("if(ResponseType.XML.name().equals(type.name())) {" + ln);
            		for(String str : paramsValue) {
            			src.append("if(!XmlUtils.isXML(").append(str).append(")) {");
            				src.append(str).append("=\"<").append(str).append(">\"+").append(str).append("+\"</").append(str).append(">\";");
            			src.append("}" + ln);
            		}
            	src.append("}else if(ResponseType.JSON.name().equals(type.name())) {" + ln);
	            	for(String str : paramsValue) {
	        			src.append("if(!GsonUtils.isJson(").append(str).append(")) {");
	        				src.append(str).append("=\"{").append(str).append(":\"+").append(str).append("+\"}\";");
	        			src.append("}" + ln);
	        		}
            	 src.append("}" + ln);
            src.append("}" + ln);
            src.append("Object o = this.h.invoke(this,m,[").append(StrUtils.join(paramsValue, ",")).append("] as Object[]);").append(ln);
            src.append("return o.toString();");
            src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
            src.append("return \"\";");
            src.append("}" + ln);
        }
        src.append("}");
        return src.toString();
    }
   
    
    public static String getUnSeqPackage(String packageName){
    	String[] packages = packageName.split("\\.");
		StringBuilder sb = new StringBuilder();
		for(int i = packages.length-1;i>=0;i--){
			sb.append(packages[i]).append(".");
		}
		String result = sb.toString();
		if(result.endsWith(".")){
			result = result.substring(0, result.length()-1);
		}
		return result;
    }
}
